package com.core.sdk.utils;

import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

public final class HttpUtil {

	@SuppressWarnings("unused")
	private static final String TAG = HttpUtil.class.getSimpleName();

	/** 从连接池中取连接的超时时间 */
	public static final int TIME_OUT_POOL = 1000*2;

	/** 套接字处理超时时间 */
	public static final int TIME_OUT_SOCKET = 1000 * 30;

	/** 连接超时时间 */
	public static final int TIME_OUT_CONNECTION = 1000 * 10;

	/** 默认字符体 */
	public static final Charset CHARSET_DEFAULT = Charset.forName(HTTP.UTF_8);

	/** 接收或传输HTTP消息时,socket内部缓冲区大小 */
	private static final int SOCKET_BUFFER_SIZE_DEFAULT = 8192;

	/** 线程池中的最大连接数 */
	private static final int MAX_CONNECTIONS_DEFAULT = 1000;

	/** 对同一个目标机器的最大并发连接数,默认值为2,如果 不设置这个参数值默认情况下对于同一个目标机器的最大并发连接只有2个 */
	private static final int MAX_PER_ROUTE = 20;

	/**
	 * @param url
	 *            请求的URL
	 * @param method
	 *            提交方式
	 * @param params
	 *            参数列表
	 * @param sendType
	 *            参数的传递方式
	 * @return 返回指定的类型 不支持图片类型
	 * @throws Exception
	 */
	public static final HttpUriRequest buildRequest(String url, Method method, Object params, ParamSendType sendType) throws Exception {
		HttpUriRequest request = null;
		switch (method) {
		case POST:
			request = createRequest_Post(url, params, sendType);
			break;
		case GET:
			request = createRequest_Get(url);
			break;
		case PUT:
			request = createRequest_Put(url, params, sendType);
			break;
		case DELETE:
			request = createRequest_Delete(url);
			break;
		default:
			request = createRequest_Get(url);
			break;
		}
		return request;
	}

	public static final HttpResponse execute(HttpUriRequest request) throws Exception {
		return execute(request, null);
	}

	/**
	 * @param request
	 * @param resultType
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static final <T> T execute(HttpUriRequest request, Type resultType) throws Exception {
		HttpResponse response = getHttpClient().execute(request);
		if (resultType == null || resultType == HttpResponse.class) {
			return (T) response;
		}
		final int code = response.getStatusLine().getStatusCode();
		if (code != 200) {
			throw new RuntimeException("http response code "+code+" invalid");
		}
		if (resultType == java.lang.Void.TYPE) {
			return null;
		}
		if (resultType == String.class) {
			String jsonStr = getStringFromInputStream(response.getEntity().getContent());
			return (T) jsonStr;
		}
		InputStream in = response.getEntity().getContent();
		InputStreamReader reader = new InputStreamReader(in);
		T t = null ;
		try {
			t = GsonUtil.getGson().fromJson(reader, resultType);
		} finally {
			closeInputStreamReader(reader);
			closeInputStream(in);
		}
		return t;
	}
	
//	/** 此方法应在调用Http方法之前就调用 */
//	public static void setUserAgent(String ua){
//		HttpUtil.userAgent = ua;
//		HttpProtocolParams.setUserAgent(httpParams,userAgent);
//	}

	private static DefaultHttpClient httpClient = null;
	private static final HttpParams httpParams = new BasicHttpParams();
	private static HttpClient getHttpClient() {
		if (httpClient != null) {
			return httpClient;
		}
		ConnManagerParams.setTimeout(httpParams, TIME_OUT_POOL);
		ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(MAX_PER_ROUTE));
		ConnManagerParams.setMaxTotalConnections(httpParams, MAX_CONNECTIONS_DEFAULT);

		HttpConnectionParams.setConnectionTimeout(httpParams, TIME_OUT_CONNECTION);
		HttpConnectionParams.setSoTimeout(httpParams, TIME_OUT_SOCKET);
		HttpConnectionParams.setStaleCheckingEnabled(httpParams, false);
		HttpConnectionParams.setTcpNoDelay(httpParams, true);
		HttpConnectionParams.setSocketBufferSize(httpParams, SOCKET_BUFFER_SIZE_DEFAULT);

		HttpProtocolParams.setUseExpectContinue(httpParams, true);
		HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
		HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);
//		HttpProtocolParams.setUserAgent(httpParams,getDefaultUserAgent());

		HttpClientParams.setRedirecting(httpParams, false);

		SchemeRegistry schemeRegistry = new SchemeRegistry();
		schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
		schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
		ClientConnectionManager manager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);
		httpClient = new DefaultHttpClient(manager, httpParams);
		return httpClient;
	}
	
//	private static String userAgent = null;
//	private static String getDefaultUserAgent(){
//		if(userAgent != null)
//			return userAgent;
//		String userAgent = String.format("(Linux; Android %s; %s Build/%s)",Build.VERSION.RELEASE, Build.MANUFACTURER, Build.ID);
//		return userAgent;
//	}
	
	private final static HttpPost createRequest_Post(String url, final Object params, ParamSendType type) throws Exception {
		HttpPost httpPost = new HttpPost(url);
		if (type == ParamSendType.byteArray) {
			ByteArrayEntity arrayEntity = convertToByteArrayEntity(params);
			httpPost.setEntity(arrayEntity);
			return httpPost;
		}
		httpPost.setEntity(new UrlEncodedFormEntity(buildParams(params), HTTP.UTF_8));
		return httpPost;
	}

	private final static HttpGet createRequest_Get(String url) throws Exception {
		HttpGet httpGet = new HttpGet(url);
		return httpGet;
	}

	private final static HttpPut createRequest_Put(String url, final Object params, ParamSendType type) throws Exception {
		HttpPut httpPut = new HttpPut(url);
		if (type == ParamSendType.byteArray) {
			ByteArrayEntity arrayEntity = convertToByteArrayEntity(params);
			httpPut.setEntity(arrayEntity);
			return httpPut;
		}
		httpPut.setEntity(new UrlEncodedFormEntity(buildParams(params), HTTP.UTF_8));
		return httpPut;
	}

	private final static HttpDelete createRequest_Delete(String url) throws Exception {
		HttpDelete httpDelete = new HttpDelete(url);
		return httpDelete;
	}

	private static ByteArrayEntity convertToByteArrayEntity(Object params) {
		String strParams = GsonUtil.getGson().toJson(params);
		ByteArrayEntity arrayEntity = new ByteArrayEntity(strParams.getBytes());
		arrayEntity.setContentType("application/octet-stream");
		return arrayEntity;
	}

	@SuppressWarnings("unchecked")
	private final static List<NameValuePair> buildParams(final Object params) {
		List<NameValuePair> listParams = new ArrayList<NameValuePair>();
		if(!(params instanceof Map)){
			return listParams;
		}
		Map<String,String> map = (Map<String,String>)params;
		if (params != null && map.size() > 0) {
			for (String key : map.keySet()) {
				listParams.add(new BasicNameValuePair(key,map.get(key)));
			}
		}
		return listParams;
	}

	public static final String getStringFromInputStream(InputStream in) throws IOException {
		BufferedInputStream bis = new BufferedInputStream(in);
		StringBuffer sb = new StringBuffer();
		int r = -1;
		byte[] buffer = new byte[1024];
		try {
			while ((r = bis.read(buffer, 0, buffer.length)) != -1) {
				sb.append(new String(buffer, 0, r));
			}
		} finally {
			if (bis != null) {
				bis.close();
			}
			if (in != null) {
				in.close();
			}
		}
		return sb.toString();
	}

	public static enum Method {
		POST, GET, PUT, DELETE
	}

	public static enum ParamSendType {
		byteArray, text
	}

	public static void closeInputStream(InputStream is){
		if(is == null)
			return ;
		try {
			is.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		is = null;
	}
	
	public static void closeInputStreamReader(Reader reader){
		if(reader == null)
			return ;
		try {
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		reader = null;
	}
	
	public static void closeFileOutPutStream(FileOutputStream fos) {
		if (fos == null)
			return;
		try {
			fos.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			fos = null;
		}
	}

	public static void closeInputStream(InputStream is, HttpUriRequest request) {
		if (is == null)
			return;
		try {
			try {
				request.abort();
			} catch (Exception e) {
				e.printStackTrace();
			}
			is.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			is = null;
		}
	}
}
